<?php

class QueryManager{

/*** Declare instance ***/
private static $instance = NULL;

/**
*
* the constructor is set to private so
* so nobody can create a new instance using new
*
*/
private function __construct() {
  /*** maybe set the db name here later ***/
}

 // getInstance method 
  public static function getInstance() { 

    if(!self::$instance) { 
      self::$instance = new self(); 
    } 

    return self::$instance; 

  } 


public function iniConnection($endpoint){
//TODO: discuss missing prefixes

        $db = sparql_connect($endpoint);
        if( !$db ) { print sparql_errno() . ": " . sparql_error(). "\n"; exit; }

		
		sparql_ns("rdfs","http://www.w3.org/2000/01/rdf-schema#");
		sparql_ns("geo","http://geo.govdata.ie/");
		sparql_ns("owl","http://www.w3.org/2002/07/owl#");
		sparql_ns("rdf","http://www.w3.org/1999/02/22-rdf-syntax-ns#");
		sparql_ns("code-age2","http://stats.govdata.ie/codelist/age2/");
		sparql_ns("code-age1","http://stats.govdata.ie/codelist/age1/");
		sparql_ns("code","http://stats.govdata.ie/codelist/");
		sparql_ns("sdmx","http://purl.org/linked-data/sdmx#");
		sparql_ns("skos","http://www.w3.org/2004/02/skos/core#");
		sparql_ns("code-birthplace","http://stats.govdata.ie/codelist/birthplace/");
		sparql_ns("code-ethnic-group","http://stats.govdata.ie/codelist/ethnic-group/");
		sparql_ns("xsd","http://www.w3.org/2001/XMLSchema#");
		sparql_ns("code-geo","http://stats.govdata.ie/codelist/geo/");
		sparql_ns("code-marital","http://stats.govdata.ie/codelist/marital-status/");
		sparql_ns("code-nationality","http://stats.govdata.ie/codelist/nationality/");
		sparql_ns("code-religion","http://stats.govdata.ie/codelist/religion/");
		sparql_ns("code-residence","http://stats.govdata.ie/codelist/usual-residence/");
		sparql_ns("concept","http://stats.govdata.ie/concept/");
		sparql_ns("sdmx-concept","http://purl.org/linked-data/sdmx/2009/concept#");
		sparql_ns("prop","http://stats.govdata.ie/property/");
		sparql_ns("qb","http://purl.org/linked-data/cube#");
		sparql_ns("sdmx-dimension","http://purl.org/linked-data/sdmx/2009/dimension#");
		sparql_ns("dsd","http://stats.govdata.ie/dsd/");
		sparql_ns("data","http://stats.govdata.ie/data/");
		sparql_ns("sdmx-metadata","http://purl.org/linked-data/sdmx/2009/metadata#");
		sparql_ns("year","http://reference.data.gov.uk/id/year/");
		sparql_ns("dcterms","http://purl.org/dc/terms/");
		sparql_ns("co","http://www.example.org/co#");
		sparql_ns("dc","http://purl.org/dc/terms/");
		sparql_ns("foaf","http://xmlns.com/foaf/0.1/");
		sparql_ns("org","http://www.w3.org/ns/org#");

        
}




public function  getIsObservationQuery($ob_uri){
$sparql="select distinct  ?measureLabel ?measure ?obsValue 
	where {
	    <".$ob_uri."> rdf:type qb:Observation.
        <".$ob_uri."> qb:dataset ?dataset.
        ?dataset qb:structure ?dsd.
        ?dsd a qb:DataStructureDefinition.
	    ?dsd qb:component ?node.
		?node qb:measure ?measure.
        ?measure  a qb:MeasureProperty;rdfs:label ?measureLabel .
        <".$ob_uri."> ?measure  ?obsValue .
        }";
//echo $sparql;
        return $sparql;
}

private function getDirectDimensionValueQuery($dim,$obs){

$sparql="
select distinct ?dimvaluri ?dimval
where
{
  <".$obs->observationURI."> <".$dim->URI."> ?dimvaluri.
  Optional{ ?dimvaluri a  skos:Concept; skos:prefLabel ?dimval.}
  Optional{ ?dimvaluri rdfs:label ?dimval.}
}";

//echo $sparql;
return $sparql;

}

private function getIndirectDimensionValueQuery($dim,$obs){

$sparql="";
if(strcmp($dim->attachmentLevel,"http://purl.org/linked-data/cube#slice")==0){

$sparql="
  
select distinct ?dimvaluri ?dimval
where {
        <".$obs->observationURI.">  qb:dataset ?dataset.
        ?dataset qb:slice ?slice.
        ?slice <".$dim->URI."> ?dimvaluri.
		Optional{ ?dimvaluri a  skos:Concept; skos:prefLabel ?dimval.}
		Optional{ ?dimvaluri a  skos:Concept; rdfs:label ?dimval.}
}";

}
else
{
// if attachemnet level qb:DataSet
$sparql="
select distinct ?dimvaluri ?dimval

where {
            <".$obs->observationURI.">  qb:dataset ?dataset.
            ?dataset  <".$dim->URI."> ?dimvaluri.
			Optional{ ?dimvaluri a  skos:Concept; skos:prefLabel ?dimval.}
            Optional{ ?dimvaluri a  skos:Concept; rdfs:label ?dimval.}
}";

}

return $sparql;

}




public function getDimensionValueQuery ($dim,$obs){
        $sparql="";
		if($dim->isIndirect==true){

		$sparql=$this->getIndirectDimensionValueQuery($dim,$obs);
		}
		else
		{
		$sparql=$this->getDirectDimensionValueQuery($dim,$obs);
		}

return $sparql;
}

//CSO_RECOMMENDATION : cso data dose not have dimension values on the slice or dataset level
public function getIndirectAttributeValueQuery($att,$obs){
$sparql="";
//echo $att->attachmentLevel;
if(strcmp($att->attachmentLevel,"http://purl.org/linked-data/cube#DataSet")==0){

$sparql="
select distinct ?attvaluri ?attval
       
where {
			 <".$obs->observationURI.">  qb:dataset ?dataset.
             ?dataset  <".$att->URI."> ?attvaluri.
			 Optional{ ?attvaluri a  skos:Concept; skos:prefLabel ?attval.}
			 Optional{ ?attvaluri a  skos:Concept; rdfs:label ?attval.}
}";

}
else
{

$sparql="
select distinct ?attvaluri ?attval
       
where {
			 <".$obs->observationURI.">  qb:dataset ?dataset.
             ?dataset   qb:slice ?slice.
             ?slice <".$att->URI."> ?attvaluri.
			 Optional{ ?attvaluri a  skos:Concept; skos:prefLabel ?attval.}
			 Optional{ ?attvaluri a  skos:Concept; rdfs:label ?attval.}
}";

}
return $sparql;
}
public function getDirectAttributeValueQuery($att,$obs){
$sparql="
select ?attvaluri ?attval
       
where {
<".$obs->observationURI.">  <".$att->URI."> ?attvaluri.
			 Optional{ ?attvaluri a  skos:Concept; skos:prefLabel ?attval.}
			 Optional{ ?attvaluri a  skos:Concept; rdfs:label ?attval.}
}";

return $sparql;

}


public function getAttributeValueQuery($att,$obs){

   $sparql="";
		if($att->isIndirect==true){

		$sparql=$this->getIndirectAttributeValueQuery($att,$obs);
		}
		else
		{
		$sparql=$this->getDirectAttributeValueQuery($att,$obs);
		}
//echo $sparql;
return $sparql;
}



public function getTraverseDimensionObservationQuery($dir,$dim_val,$msr_uri,$dim_uri,$ob_uri,$wrappeddim){
$sparql="select ?uri ?obsval ?dimensionValue ?next         where {";
$sparql.=" ?uri rdf:type qb:Observation.";
//measure stmt
$sparql.=" ?uri <".$msr_uri."> ?obsval. ";
$sparql.=" ?uri qb:dataset ?dataset.";

for($i=0;$i<count($wrappeddim["dimensions"]);$i++){
$dim=$wrappeddim["dimensions"][$i];
$dimvalue=$wrappeddim["values"][$i];    

		if(strcmp($dim->URI,$dim_uri)==0){
				if($dim->isIndirect==true){
                 $sparql.="?dataset qb:slice ?slice. ?slice <".$dim->URI."> ?next. ";
				}
				else{
				$sparql.=" ?uri <".$dim->URI."> ?next. ";
				}
		}
		else{

				if($dim->isIndirect==true){
                 $sparql.="?dataset qb:slice ?slice. ?slice <".$dim->URI."> <".$dimvalue->valueURI.">.";
				 if(strcmp($dimvalue->value,"")>0){
				  $sparql.="Optional{<".$dimvalue->valueURI."> a  skos:Concept; skos:prefLabel ?lab . filter (str(?lab)=str(\"".$dimvalue->value."\")) } ";
				 }
				}
				else{
				$sparql.=" ?uri <".$dim->URI."> <".$dimvalue->valueURI.">.";
				if(strcmp($dimvalue->value,"")>0){
				  $sparql.="Optional{<".$dimvalue->valueURI."> a  skos:Concept; skos:prefLabel ?lab . filter (str(?lab)=str(\"".$dimvalue->value."\")) } ";
				}
				}
		}

}
$sparql.= " ?next a  skos:Concept; skos:prefLabel ?dimensionValue.";
if(strcmp($dir,'next')==0){  
$sparql.=  " filter (str(?dimensionValue) > str(\"".$dim_val."\"))";
$sparql.=" }order by asc(?dimensionValue) limit 1";
  }
else
if(strcmp($dir,'pre')==0)
{
$sparql.=  " filter (str(?dimensionValue) < str(\"".$dim_val."\"))";
$sparql.=" }order by desc(?dimensionValue) limit 1";
}  
else
{
$sparql.=  " filter (str(?dimensionValue) = str(\"".$dim_val."\"))";
$sparql.=" }order by desc(?dimensionValue) limit 1";
}  


//print "inside query".$sparql;   
return $sparql;

}


//CSO_RECOMMENDATION :  using qb:codelist and qb:concept intstead of rdfs:range
public function getDimensionValueURIByDirectionQuery($dim_uri,$dim_val,$dir){
$sparql="select ?dimvaluri ?dimval         where { <".$dim_uri."> a qb:DimensionProperty.
<".$dim_uri."> rdfs:range ?type.
?dimvaluri a ?type,skos:Concept;skos:prefLabel ?dimval. ";

   if(strcmp($dir,"next")==0){
	 $sparql.="filter (str(?dimval) > str('".$dim_val."'))
	} 
	order by asc(?dimval)
	limit 1
	";
	}
	else if(strcmp($dir,"pre")==0){

	$sparql.="filter (str(?dimval) < str('".$dim_val."'))
	} 
	order by desc (?dimval)
	limit 1
	";
	}
	else
	{

	$sparql.="filter (str(?dimval) = str('".$dim_val."'))
	} 
	order by desc (?dimval)
	limit 1
	";
	}

return $sparql;
}
//CSO_RECOMMENDATION : cso data dose not have dimension values on the slice or dataset level
public function  getDimensionObservationsQuery($dim_uri_val,$dim_uri,$indirect){


        $sparql="";
		
			if(strcmp($indirect,"0")==0){
				$sparql=$this->getIndirectDimensionQuery($dim_uri_val,$dim_uri);
			}
			else
			{
				$sparql=$this->getDirectDimensionQuery($dim_uri_val,$dim_uri);
			}
		

return $sparql;
}

private function getIndirectDimensionQuery($dim_uri_val,$dim_uri){

$sparql="
select ?uri
       
where {
?uri  qb:dataset ?dataset.
             ?dataset qb:slice ?slice.
             ?slice <".$dim_uri."> <".$dim_uri_val.">.
			}";

return $sparql;

}


private function getDirectDimensionQuery($dim_uri_val,$dim_uri){

$sparql="
select ?uri
       
where
{
  ?uri  <".$dim_uri."> <".$dim_uri_val.">.
}";


return $sparql;

}
//CSO_RECOMMENDATION : ok add some namesopaces but no data available using sdmx-metadata:title  
public function getDataSetMetadataQuery($obs_uri){

$sparql="

select ?ds ?label ?title ?comment ?date ?subject ?publisher          where {
        ?ds a qb:DataSet.
		Optional {?ds rdfs:label ?label.}
		Optional {?ds sdmx-metadata:title ?title.}
        Optional {?ds rdfs:comment ?comment}
         Optional {?ds dcterms:date ?date}
         Optional {?ds  dc:publisher ?organization}
        <".$obs_uri."> a qb:Observation;
        qb:dataset ?ds .
         Optional {?organization a org:Organization, foaf:Agent;
        rdfs:label ?publisher}

        optional {?ds dcterms:subject ?subject . Filter (isLiteral(?subject))}
}";

//echo $sparql;
return $sparql;


}


//CSO_RECOMMENDATION : using qb:codelist and qb:concept intstead of rdfs:range
public function getDimensionMetadataQuery($dim_uri){

$sparql="select Distinct  ?dimensionLabel ?valueuri ?valuelabel ?comment 
     where {
		<".$dim_uri."> a qb:DimensionProperty;rdfs:label ?dimensionLabel.
		
		Optional {?valueuri skos:prefLabel ?valuelabel. 
		<".$dim_uri."> rdfs:range ?range.
		?valueuri a ?range. }
		Optional { ?valueuri a skos:Concept;
		skos:prefLabel ?valuelabel. 
		<".$dim_uri."> qb:codeList ?codelist.?valueuri skos:inScheme ?codelist. }
		Optional {<".$dim_uri."> rdfs:comment ?comment}}
		";

//echo $sparql;
return $sparql;



}
//CSO_RECOMMENDATION : ok
public function getMeasureMetadataQuery($measure_uri){


$sparql="select Distinct ?measureLabel  ?comment	        where {
		<".$measure_uri."> a qb:MeasureProperty;rdfs:label ?measureLabel .
		optional {<".$measure_uri.">  rdfs:comment ?comment}}";

return $sparql;



}
//CSO_RECOMMENDATION : 
public function getTraverseMeasureObservationQuery($dir,$measure_lab,$measure_uri,$wrappeddim){



//TODO: discuss the attachment level

$sparql="select ?uri          where {";
$sparql.=" ?uri rdf:type qb:Observation.";
//measure stmt
$sparql.=" ?uri ?measure ?obsval. ";
$sparql.=" ?uri qb:dataset ?dataset.";

	for($i=0;$i<count($wrappeddim["dimensions"]);$i++){
		$dim=$wrappeddim["dimensions"][$i];
		$dimvalue=$wrappeddim["values"][$i];    
					if($dim->isIndirect==true){
					$sparql.=" ?dataset qb:slice ?slice .?slice <".$dim->URI."> <".$dimvalue->valueURI.">.";
						if(strcmp($dimvalue->value,"")>0){
						$sparql.="Optional{<".$dimvalue->valueURI."> a  skos:Concept; skos:prefLabel ?lab . filter (str(?lab)=str(\"".$dimvalue->value."\")) } ";
						}
					}
					else{
					$sparql.=" ?uri <".$dim->URI."> <".$dimvalue->valueURI.">.";
						if(strcmp($dimvalue->value,"")>0){
						$sparql.="Optional{<".$dimvalue->valueURI."> a  skos:Concept; skos:prefLabel ?lab . filter (str(?lab)=str(\"".$dimvalue->value."\")) } ";
						}
					}
	}

$sparql.= "  ?measure a qb:MeasureProperty;rdfs:label ?measureLabel.";
	if(strcmp($dir,'next')==0){  
			$sparql.=  " filter (str(?measureLabel) > str(\"".$measure_lab."\"))";
			$sparql.=" }order by asc(?measureLabel) limit 1";
	  }
	else{
			$sparql.=  " filter (str(?measureLabel) < str(\"".$measure_lab."\"))";
			$sparql.=" }order by desc(?measureLabel) limit 1";
	}  



return $sparql;
}
//CSO_RECOMMENDATION : ok add some namesopaces but no data available using sdmx-metadata:title  
function getDataSetMetadataQuerydsURI($datasetURI){

$sparql="select ?label ?title ?comment ?date ?subject ?publisher         where {
		<".$datasetURI."> a qb:DataSet;
		Optional {<".$datasetURI.">  rdfs:label ?label.}
		Optional {<".$datasetURI.">  sdmx-metadata:title ?title.}
		OPTIONAL {<".$datasetURI."> rdfs:comment ?comment}
		OPTIONAL {<".$datasetURI."> dcterms:date ?date}
		OPTIONAL {<".$datasetURI."> dc:publisher ?organization}
		OPTIONAL {?organization a org:Organization, foaf:Agent;
		rdfs:label ?publisher }

		optional {?ds dcterms:subject ?subject . Filter (isLiteral(?subject))}
}";

//echo $sparql;
return $sparql;

}
//CSO_RECOMMENDATION : ok
function getTypeQuery($uri){

$sparql="select ?type where {
		<".$uri."> a ?type.
		}";

return $sparql;


}
//CSO_RECOMMENDATION : not compatible
function getStructureDefinitionQueryAttributes($uri){

$sparql="
select distinct ?attributeLabel ?att  ?attribute  ?order where {
	<".$uri."> rdf:type qb:Observation.
    <".$uri."> qb:dataset ?dataset.
    ?dataset qb:structure ?dsd.
	?dsd a qb:DataStructureDefinition.
	?dsd qb:component ?node.
	?node qb:attribute ?attribute.
	
    Optional {?node qb:componentAttachment ?att.}
    Optional {?node qb:order ?order.}	
}
order by ?order";


return $sparql;


}
//CSO_RECOMMENDATION : not compatible
function getStructureDefinitionQueryDimension($uri){

$sparql=" 
select distinct ?dimensionLabel ?dimension  ?att ?order  where {
   
		<".$uri."> rdf:type qb:Observation.
        <".$uri."> qb:dataset ?dataset.
        ?dataset qb:structure ?dsd.
        ?dsd a qb:DataStructureDefinition .
		?dsd qb:component ?node.
		?node qb:dimension ?dimension.
		?dimension a qb:DimensionProperty;rdfs:label ?dimensionLabel.
        Optional {?node qb:componentAttachment ?att.}	
        Optional {?node qb:order ?order.}	     
}
order by ?order";

return $sparql;



}
//CSO_RECOMMENDATION:  Changed 
function getdatasetMetadataAndObservationsQuery($uri){

$sparql='select ?uri ?dimensionLabel ?valueuri ?val  ?measureLabel  ?obsValue        
where {
?uri qb:dataset <'.$uri.'>.
?uri a qb:Observation.
<'.$uri.'> qb:structure  ?dsd.
?dsd qb:component [qb:dimension ?dimension].
?dsd qb:component [qb:measure ?measure].
?uri  ?measure  ?obsValue .
?measure  a qb:MeasureProperty;rdfs:label ?measureLabel .
Optional {?uri ?dimension ?valueuri}
Optional {<'.$uri.'> ?dimension ?valueuri}
Optional {<'.$uri.'> qb:slice ?slice. ?slice ?dimension ?valueuri}
Optional{ ?valueuri a  skos:Concept; skos:prefLabel ?val.}
Optional{ ?valueuri a  skos:Concept; rdfs:label ?val.}
?dimension a qb:DimensionProperty;rdfs:label ?dimensionLabel.
FILTER ( str(?dimension) != str("http://purl.org/linked-data/cube#measureType") )
}
order by ?uri
limit 1000

';

return $sparql;


}
//CSO_RECOMMENDATION:  Changed 
function getAllDimensionsLabelsUnderScoreSeperatedNamesQuery($uri){

$sparql='select Distinct ?dimensionLabel
where {
<'.$uri.'> qb:structure  ?dsd.
?dsd qb:component [qb:dimension ?dimension].
?dimension a qb:DimensionProperty.
Optional {?dimension rdfs:label ?dimensionLabel.}
FILTER ( str(?dimension) != str("http://purl.org/linked-data/cube#measureType") )
}
order by ?dimensionLabel

';

//what about sdmx-dimension:refPeriod?


return $sparql;

}
//CSO_RECOMMENDATION: OK
function getNoObservationOfDimensionValueQuery($value_uri,$dimension){
$sparql='
select Distinct  ?obser         where {
?obser a qb:Observation.
{

?obser <'.$dimension.'> <'.$value_uri.'>.
}
union 
{
?obser qb:dataset ?dataset.
?dataset <'.$dimension.'> <'.$value_uri.'>.

}
union 
{

?obser qb:dataset ?dataset.
?dataset qb:slice ?slice.
?slice <'.$dimension.'> <'.$value_uri.'>.

}

}
';
//echo $sparql;
return $sparql;
}



}
?>
